﻿namespace TriangleGames.TrainResEditor
{
    using TriangleGames.TrainRes;
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Runtime.InteropServices;
    using UnityEditor;
    using UnityEngine;

    public class GlobalVariablesWindow : EditorWindow
    {
        private static bool autoScroll;
        private bool editingStateName;
        private List<FsmVariable> globalVariables;
        private static GlobalVariablesWindow instance;
        private bool listIsDirty;
        private string newVariableName = "";
        private VariableType newVariableType;
        private bool resetKeyboard;
        private Vector2 scrollPosition;
        private static float scrollViewHeight;
        private int selectedIndex = -1;
        private static Rect selectedRect;
        private string selectedVariableName = "";
        private bool sortByVariableType;
        private readonly List<FsmVariable> unusedVariables = new List<FsmVariable>();
        private readonly Dictionary<NamedVariable, List<FsmInfo>> usage = new Dictionary<NamedVariable, List<FsmInfo>>();
        private readonly Dictionary<NamedVariable, int> usageCount = new Dictionary<NamedVariable, int>();

        private static void AddVariable(VariableType type, string name, [Optional, DefaultParameterValue(true)] bool undo)
        {
            if (undo)
            {
                FsmEditor.RegisterUndo(FsmVariables.GlobalsComponent, "添加全局变量");
            }
            FsmVariable.AddVariable(FsmVariables.GlobalVariables, type, name);
            FsmEditor.SaveGlobals();
        }

        private void BuildGlobalVariableList()
        {
            this.globalVariables = FsmVariable.GetFsmVariableList(FsmVariables.GlobalVariables, FsmVariables.GlobalsComponent);
            this.listIsDirty = false;
        }

        private void ChangeVariableType(FsmVariable fsmVariable, VariableType newType)
        {
            if (this.CheckDeleteVariable("修改变量类型", "该变量正在被使用! 你是否想改变它的类型?", fsmVariable))
            {
                FsmEditor.RegisterUndo(FsmVariables.GlobalsComponent, "改变全局变量类型");
                string name = fsmVariable.Name;
                this.DeleteVariable(fsmVariable, false, false);
                AddVariable(newType, name, false);
                FsmBuilder.RemoveVariableUsage(fsmVariable.NamedVar);
                this.listIsDirty = true;
                FsmEditor.SaveGlobals();
            }
        }

        private bool CheckDeleteVariable(string dialogTitle, string warning, FsmVariable fsmVariable)
        {
            this.UpdateUseCount();
            if (!this.unusedVariables.Contains(fsmVariable))
            {
                return EditorUtility.DisplayDialog(dialogTitle, warning, "是", "否");
            }
            return true;
        }

        private void DeleteUnusedVariables()
        {
            this.UpdateUseCount();
            if (this.unusedVariables.Count == 0)
            {
                EditorUtility.DisplayDialog("删除未使用的全局变量", "没有未使用变量...", "OK");
            }
            else
            {
                if (EditorUtility.DisplayDialog("删除未使用的全局变量", "你确定要删除 " + this.unusedVariables.Count + " 个未使用的全局变量?", "是", "否"))
                {
                    FsmEditor.RegisterUndo(FsmVariables.GlobalsComponent, "删除未使用全局变量");
                    foreach (FsmVariable variable in this.unusedVariables)
                    {
                        this.DeleteVariable(variable, false, false);
                    }
                    this.Reset();
                }
                FsmEditor.SaveGlobals();
            }
        }

        private void DeleteVariable(FsmVariable fsmVariable, [Optional, DefaultParameterValue(true)] bool undo, [Optional, DefaultParameterValue(true)] bool checkDialog)
        {
            if (!checkDialog || this.CheckDeleteVariable("删除变量", "该变量正在被使用! 你确定要删除它?", fsmVariable))
            {
                if (FsmEditorSettings.LoadAllPrefabs)
                {
                    FsmEditorUtility.LoadAllPrefabsInProject();
                }
                FsmBuilder.RemoveVariableUsage(fsmVariable.NamedVar);
                FsmVariable.DeleteVariable(FsmVariables.GlobalVariables, fsmVariable);
                this.listIsDirty = true;
                FsmEditor.SaveGlobals();
            }
        }

        public void Deselect()
        {
            this.resetKeyboard = true;
            this.selectedVariableName = "";
            this.newVariableName = "";
            this.selectedIndex = -1;
            base.Repaint();
        }

        private void DoAutoScroll()
        {
            if ((this.selectedVariableName != "") && ((Event.current.type == EventType.Repaint) && autoScroll))
            {
                scrollViewHeight = GUILayoutUtility.GetLastRect().height;
                if (selectedRect.y < 0f)
                {
                    this.scrollPosition.y += selectedRect.y;
                    base.Repaint();
                }
                else if ((selectedRect.y + selectedRect.height) > scrollViewHeight)
                {
                    this.scrollPosition.y += (selectedRect.y + selectedRect.height) - scrollViewHeight;
                    base.Repaint();
                }
                autoScroll = false;
            }
        }

        private void DoTableHeaders()
        {
            EditorGUILayout.BeginHorizontal(new GUILayoutOption[0]);
            bool changed = GUI.changed;
            GUI.changed = false;
            GUILayout.BeginHorizontal(FsmEditorStyles.TableRowBox, new GUILayoutOption[0]);
            this.sortByVariableType = !GUILayout.Toggle(!this.sortByVariableType, new GUIContent("名称", "右键点击变量查看哪些状态机使用了该变量."), FsmEditorStyles.TableRowHeader, new GUILayoutOption[0]);
            GUILayout.FlexibleSpace();
            GUILayout.Label(new GUIContent("使用", "全局变量被使用的次数."), new GUILayoutOption[0]);
            GUILayout.Space(10f);
            this.sortByVariableType = GUILayout.Toggle(this.sortByVariableType, new GUIContent("类型", "查看/修改 变量类型."), FsmEditorStyles.TableRowHeader, new GUILayoutOption[0]);
            GUILayout.Space(65f);
            if (FsmEditorGUILayout.SettingsButtonPadded())
            {
                this.GenerateVariableManagerMenu().ShowAsContext();
            }
            GUILayout.EndHorizontal();
            if (GUI.changed)
            {
                this.SortVariableList();
            }
            else
            {
                GUI.changed = changed;
            }
            EditorGUILayout.EndHorizontal();
        }

        private void DoVariableEditor()
        {
            EditorGUIUtility.LookLikeControls(100f);
            FsmEditorGUILayout.Divider(new GUILayoutOption[0]);
            EditorGUILayout.BeginHorizontal(new GUILayoutOption[0]);
            GUI.SetNextControlName("EditVariableNameTextField");
            this.newVariableName = EditorGUILayout.TextField(string.IsNullOrEmpty(this.selectedVariableName) ? new GUIContent("新变量", "添加新变量到状态机. 变量用于动作存储信息.") : new GUIContent("修改变量", "修改选定的变量."), this.newVariableName, new GUILayoutOption[0]);
            bool flag = this.IsValidVariableName(this.selectedVariableName, this.newVariableName);
            EditorGUILayout.EndHorizontal();
            FsmVariable fsmVariable = this.GetVariable(this.selectedVariableName);
            if (fsmVariable != null)
            {
                bool changed = GUI.changed;
                GUI.changed = false;
                fsmVariable.DoValueGUI(null, true);
                fsmVariable.Tooltip = EditorGUILayout.TextField(new GUIContent("提示", "提示用于观察器和动作浏览器. 不支持Vector3."), fsmVariable.Tooltip, new GUILayoutOption[0]);
                if (GUI.changed)
                {
                    this.UpdateVariable(fsmVariable, "");
                }
                else
                {
                    GUI.changed = changed;
                }
            }
            else
            {
                GUILayout.BeginHorizontal(new GUILayoutOption[0]);
                this.newVariableType = (VariableType) EditorGUILayout.Popup(new GUIContent("变量类型", "选择类型的存储信息."), (int) this.newVariableType, FsmVariable.VariableTypeNames, new GUILayoutOption[0]);
                bool enabled = GUI.enabled;
                GUI.enabled = (GUI.enabled && flag) && (this.newVariableName.Length > 0);
                if (GUILayout.Button(new GUIContent("增加"), new GUILayoutOption[] { GUILayout.MaxWidth(35f), GUILayout.MaxHeight(15f) }))
                {
                    AddVariable(this.newVariableType, this.newVariableName, true);
                    if (FsmEditorSettings.SelectNewVariables)
                    {
                        this.SelectVariable(this.newVariableName);
                    }
                    this.Reset();
                }
                GUI.enabled = enabled;
                GUILayout.EndHorizontal();
            }
            if (Event.current.type == EventType.KeyUp)
            {
                if ((this.editingStateName && flag) && FsmEditorUtility.CommitKeyPressed())
                {
                    if (string.IsNullOrEmpty(this.selectedVariableName))
                    {
                        AddVariable(this.newVariableType, this.newVariableName, true);
                        if (FsmEditorSettings.SelectNewVariables)
                        {
                            this.SelectVariable(this.newVariableName);
                        }
                        this.Reset();
                    }
                    else
                    {
                        this.RenameVariable(this.selectedVariableName, this.newVariableName);
                        this.selectedVariableName = this.newVariableName;
                    }
                    GUIUtility.ExitGUI();
                    return;
                }
                this.editingStateName = GUI.GetNameOfFocusedControl() == "EditVariableNameTextField";
                if (Event.current.keyCode == KeyCode.Escape)
                {
                    this.Reset();
                }
            }
            if (!flag && !string.IsNullOrEmpty(this.newVariableName))
            {
                GUILayout.Box("变量名称已经被使用!", FsmEditorStyles.ErrorBox, new GUILayoutOption[0]);
            }
            EditorGUILayout.Space();
        }

        private void DoVariableTable()
        {
            this.scrollPosition = GUILayout.BeginScrollView(this.scrollPosition, new GUILayoutOption[0]);
            if (FsmEditorSettings.ShowHints)
            {
                GUILayout.Box("全局变量能被任何状态机看到.\n右键点击变量以查看哪些状态机正在使用该变量.", FsmEditorStyles.HintBox, new GUILayoutOption[0]);
            }
            if (this.globalVariables.Count == 0)
            {
                GUILayout.BeginHorizontal(FsmEditorStyles.TableRowBox, new GUILayoutOption[0]);
                GUILayout.Label("[空]", new GUILayoutOption[0]);
                GUILayout.EndHorizontal();
            }
            for (int i = 0; i < this.globalVariables.Count; i++)
            {
                int num2;
                FsmVariable fsmVariable = this.globalVariables[i];
                bool flag = fsmVariable.Name == this.selectedVariableName;
                GUILayout.BeginVertical(new GUILayoutOption[0]);
                GUILayout.BeginHorizontal(flag ? FsmEditorStyles.SelectedEventBox : (FsmEditorSettings.DebugVariables ? FsmEditorStyles.TableRowBoxNoDivider : FsmEditorStyles.TableRowBox), new GUILayoutOption[0]);
                GUIStyle style = flag ? FsmEditorStyles.TableRowTextSelected : FsmEditorStyles.TableRowText;
                if (GUILayout.Button(new GUIContent(fsmVariable.Name, fsmVariable.Tooltip), style, new GUILayoutOption[] { GUILayout.MinWidth(base.position.width - 150f) }))
                {
                    this.SelectVariable(fsmVariable.Name);
                    if ((Event.current.button == 1) || EditorGUI.actionKey)
                    {
                        this.GenerateFsmList(fsmVariable.NamedVar).ShowAsContext();
                    }
                }
                this.usageCount.TryGetValue(fsmVariable.NamedVar, out num2);
                GUILayout.FlexibleSpace();
                GUILayout.Label(num2.ToString(CultureInfo.CurrentCulture), style, new GUILayoutOption[0]);
                GUILayout.Space(10f);
                bool changed = GUI.changed;
                GUI.changed = false;
                VariableType newType = (VariableType) EditorGUILayout.Popup((int) fsmVariable.Type, FsmVariable.VariableTypeNames, new GUILayoutOption[] { GUILayout.MaxWidth(114f) });
                if (GUI.changed)
                {
                    this.ChangeVariableType(fsmVariable, newType);
                    GUIUtility.ExitGUI();
                    return;
                }
                GUI.changed = changed;
                if (FsmEditorGUILayout.DeleteButton())
                {
                    this.DeleteVariable(fsmVariable, true, true);
                    GUIUtility.ExitGUI();
                    return;
                }
                GUILayout.EndHorizontal();
                if (FsmEditorSettings.DebugVariables)
                {
                    FsmEditorGUILayout.ReadonlyTextField(fsmVariable.NamedVar.ToString(), new GUILayoutOption[0]);
                }
                GUILayout.EndVertical();
                if (flag)
                {
                    this.selectedIndex = i;
                    if (Event.current.type == EventType.Repaint)
                    {
                        selectedRect = GUILayoutUtility.GetLastRect();
                        selectedRect.y -= this.scrollPosition.y;
                    }
                }
            }
            GUILayout.Space(20f);
            GUILayout.EndScrollView();
            this.DoAutoScroll();
            GUILayout.FlexibleSpace();
        }

        private GenericMenu GenerateFsmList(NamedVariable variable)
        {
            int num;
            List<FsmInfo> list;
            this.UpdateUseCount();
            GenericMenu menu = new GenericMenu();
            this.usageCount.TryGetValue(variable, out num);
            if (num == 0)
            {
                menu.AddDisabledItem(new GUIContent("没有状态机使用该变量..."));
                return menu;
            }
            this.usage.TryGetValue(variable, out list);
            foreach (FsmInfo info in list)
            {
                menu.AddItem(new GUIContent(FsmEditorUtility.GetFullFsmLabel(info.fsm)), FsmEditor.SelectedFsm == info.fsm, new GenericMenu.MenuFunction2(GlobalVariablesWindow.SelectFsm), info.fsm);
            }
            return menu;
        }

        private GenericMenu GenerateVariableManagerMenu()
        {
            GenericMenu menu = new GenericMenu();
            menu.AddItem(new GUIContent("调试变量的值"), FsmEditorSettings.DebugVariables, new GenericMenu.MenuFunction(EditorCommands.ToggleDebugVariables));
            menu.AddItem(new GUIContent("删除未使用的变量"), false, new GenericMenu.MenuFunction(this.DeleteUnusedVariables));
            menu.AddSeparator("");
            menu.AddItem(new GUIContent("在线帮助"), false, new GenericMenu.MenuFunction(GlobalVariablesWindow.OpenOnlineHelp));
            return menu;
        }

        private FsmVariable GetVariable(string variableName)
        {
            foreach (FsmVariable variable in this.globalVariables)
            {
                if (variable.Name == variableName)
                {
                    return variable;
                }
            }
            return null;
        }

        private bool IsValidVariableName(string fsmVariableName, string variableName)
        {
            if (string.IsNullOrEmpty(variableName))
            {
                return false;
            }
            FsmVariable variable = this.GetVariable(fsmVariableName);
            foreach (FsmVariable variable2 in this.globalVariables)
            {
                if ((variable != variable2) && (variableName == variable2.Name))
                {
                    return false;
                }
            }
            return true;
        }

        private void KeyboardGUI()
        {
            if (GUIUtility.keyboardControl == 0)
            {
                int controlID = GUIUtility.GetControlID(FocusType.Keyboard);
                if (Event.current.GetTypeForControl(controlID) == EventType.KeyDown)
                {
                    switch (Event.current.keyCode)
                    {
                        case KeyCode.UpArrow:
                            Event.current.Use();
                            this.SelectPrevious();
                            GUIUtility.ExitGUI();
                            return;

                        case KeyCode.DownArrow:
                            Event.current.Use();
                            this.SelectNext();
                            GUIUtility.ExitGUI();
                            return;

                        case KeyCode.Return:
                            Event.current.Use();
                            if (GUIUtility.keyboardControl == 0)
                            {
                                this.Deselect();
                            }
                            GUIUtility.ExitGUI();
                            return;
                    }
                }
            }
        }

        public void OnEnable()
        {
            instance = this;
            base.title = "全局变量";
            base.minSize = new Vector2(200f, 200f);
            base.autoRepaintOnSceneChange = true;
            this.Reset();
            this.listIsDirty = true;
        }

        private void OnFocus()
        {
            this.BuildGlobalVariableList();
            this.UpdateUseCount();
        }

        private void OnGUI()
        {
            if (FsmEditor.Instance == null)
            {
                base.Close();
            }
            else if (FsmEditorGUILayout.ToolWindowsCommonGUI(this))
            {
                string str;
                string str2;
                if (this.resetKeyboard)
                {
                    GUIUtility.keyboardControl = 0;
                    this.resetKeyboard = false;
                }
                if (((Event.current.type == EventType.ValidateCommand) && ((str = Event.current.commandName) != null)) && (str == "UndoRedoPerformed"))
                {
                    Event.current.Use();
                }
                if (((Event.current.type == EventType.ExecuteCommand) && ((str2 = Event.current.commandName) != null)) && (str2 == "UndoRedoPerformed"))
                {
                    this.Reset();
                }
                if (FsmVariables.GlobalVariables == null)
                {
                    GUILayout.Label("添加TrainResGlobals组件到场景中...", new GUILayoutOption[0]);
                }
                else
                {
                    this.KeyboardGUI();
                    this.DoTableHeaders();
                    this.DoVariableTable();
                    if (Event.current.type == EventType.ContextClick)
                    {
                        this.GenerateVariableManagerMenu().ShowAsContext();
                    }
                    this.DoVariableEditor();
                    if (((Event.current != null) && (Event.current.type == EventType.MouseDown)) && ((GUIUtility.hotControl == 0) && (GUIUtility.keyboardControl == 0)))
                    {
                        this.Deselect();
                    }
                }
            }
        }

        private static void OpenOnlineHelp()
        {
            EditorCommands.OpenWikiPage(WikiPages.VariableManager);
        }

        private void RenameVariable(string fsmVariableName, string newName)
        {
            FsmVariable fsmVariable = this.GetVariable(fsmVariableName);
            if (fsmVariable != null)
            {
                FsmEditor.RegisterUndo(FsmVariables.GlobalsComponent, "修改变量");
                this.UpdateVariable(fsmVariable, newName);
                FsmEditor.SaveGlobals();
                if (FsmEditorSettings.LoadAllPrefabs)
                {
                    FsmEditorUtility.LoadAllPrefabsInProject();
                }
                foreach (Fsm fsm in FsmInfo.GetFsmList(FsmInfo.FindVariableUsage(fsmVariable.NamedVar)))
                {
                    FsmEditor.SaveActions(fsm);
                }
            }
        }

        public void Reset()
        {
            if (Event.current != null)
            {
                GUIUtility.keyboardControl = 0;
            }
            this.BuildGlobalVariableList();
            this.UpdateUseCount();
            this.SanityCheckSelection();
            base.Repaint();
            FsmEditor.Repaint(true);
            FsmEditor.RepaintAll();
        }

        public static void ResetView()
        {
            if (instance != null)
            {
                instance.Reset();
                instance.listIsDirty = true;
            }
        }

        public void SanityCheckSelection()
        {
            foreach (FsmVariable variable in this.globalVariables)
            {
                if (variable.Name == this.selectedVariableName)
                {
                    return;
                }
            }
            this.Deselect();
        }

        private void SelectFirst()
        {
            this.SelectVariable(0);
        }

        private static void SelectFsm(object userdata)
        {
            EditorCommands.SelectFsm(userdata);
        }

        private void SelectLast()
        {
            this.SelectVariable((int) (this.globalVariables.Count - 1));
        }

        private void SelectNext()
        {
            if (this.selectedIndex == -1)
            {
                this.SelectLast();
            }
            else
            {
                this.SelectVariable((int) (this.selectedIndex + 1));
            }
        }

        private void SelectPrevious()
        {
            if (this.selectedIndex == -1)
            {
                this.SelectFirst();
            }
            else
            {
                this.SelectVariable((int) (this.selectedIndex - 1));
            }
        }

        private void SelectVariable(int index)
        {
            if ((index >= 0) && (index <= (this.globalVariables.Count - 1)))
            {
                this.SelectVariable(this.globalVariables[index].Name);
            }
        }

        public void SelectVariable(string variableName)
        {
            this.resetKeyboard = true;
            this.selectedVariableName = variableName;
            this.newVariableName = this.selectedVariableName;
            autoScroll = true;
        }

        private void SortVariableList()
        {
            if (this.sortByVariableType)
            {
                this.globalVariables.Sort(new Comparison<FsmVariable>(FsmVariable.CompareByType));
            }
            else
            {
                this.globalVariables.Sort();
            }
        }

        private void Update()
        {
            if (this.listIsDirty)
            {
                this.BuildGlobalVariableList();
                this.UpdateUseCount();
                base.Repaint();
            }
        }

        public void UpdateUseCount()
        {
            this.usage.Clear();
            this.usageCount.Clear();
            this.unusedVariables.Clear();
            foreach (FsmVariable variable in this.globalVariables)
            {
                List<FsmInfo> fsmInfoList = FsmInfo.FindVariableUsage(variable.NamedVar);
                List<Fsm> fsmList = FsmInfo.GetFsmList(fsmInfoList);
                this.usage.Add(variable.NamedVar, fsmInfoList);
                this.usageCount.Add(variable.NamedVar, fsmList.Count);
                if (fsmInfoList.Count == 0)
                {
                    this.unusedVariables.Add(variable);
                }
            }
        }

        private void UpdateVariable(FsmVariable fsmVariable, [Optional, DefaultParameterValue("")] string newName)
        {
            FsmEditor.RegisterUndo(FsmVariables.GlobalsComponent, "修改全局变量");
            if (!string.IsNullOrEmpty(newName))
            {
                fsmVariable.Name = newName;
            }
            this.listIsDirty = true;
            FsmEditor.SaveGlobals();
        }

        public static void UpdateView()
        {
            if (instance != null)
            {
                instance.BuildGlobalVariableList();
                instance.Repaint();
            }
        }

        public bool VariableNameExists(string variableName)
        {
            foreach (FsmVariable variable in this.globalVariables)
            {
                if (variableName == variable.Name)
                {
                    return true;
                }
            }
            return false;
        }
    }
}

